package la.iok.hzsvn.lewin.movie.service;

import la.iok.hzsvn.lewin.movie.entity.*;
import la.iok.hzsvn.lewin.movie.mapper.PlayRoleBookInstanceMapper;
import la.iok.hzsvn.lewin.movie.model.PlayRoleBookVo;
import la.iok.hzsvn.lewin.mybatis.service.BaseServiceImpl;
import la.iok.hzsvn.share.annotations.NotNull;
import la.iok.hzsvn.share.annotations.NotNullElement;
import la.iok.hzsvn.share.annotations.NullElement;
import la.iok.hzsvn.share.annotations.Nullable;
import la.iok.hzsvn.share.collection.IdOperators;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class PlayRoleBookInstanceServiceImpl extends BaseServiceImpl<PlayRoleBookInstance, PlayRoleBookInstanceMapper,Long>
        implements PlayRoleBookInstanceService {
    private final BookChapterInstanceService bookChapterInstanceService;
    private final PlayRoleInstanceService playRoleInstanceService;
    private final PlayRoleBookFileService playRoleBookFileService;
    private final PlayRoleBookImageService playRoleBookImageService;

    public PlayRoleBookInstanceServiceImpl(PlayRoleBookInstanceMapper mapper,
                                           BookChapterInstanceService bookChapterInstanceService,
                                           PlayRoleInstanceService playRoleInstanceService,
                                           PlayRoleBookFileService playRoleBookFileService,
                                           PlayRoleBookImageService playRoleBookImageService) {
        super(mapper);
        this.bookChapterInstanceService = bookChapterInstanceService;
        this.playRoleInstanceService = playRoleInstanceService;
        this.playRoleBookFileService = playRoleBookFileService;
        this.playRoleBookImageService = playRoleBookImageService;
    }

    @NotNull
    @Override
    public Long save(@NotNull PlayRoleBook book,@NotNull Long playRoleInstanceId,@NotNull Long chapterInstanceId,
                     @NotNull Long htmlId, @NotNull String htmlPath) {
        PlayRoleBookInstance entity = new PlayRoleBookInstance();
        BeanUtils.copyProperties(book,entity);
        entity.setId(null);
        entity.setPlayRoleInstanceId(playRoleInstanceId);
        entity.setChapterInstanceId(chapterInstanceId);
        entity.setPlayRoleBookId(book.getId());
        entity.setHtmlId(htmlId);
        entity.setHtmlPath(htmlPath);
        insertSelective(entity);
        return entity.getId();
    }

    @NotNull
    @NotNullElement
    @Override
    public List<PlayRoleBookInstance> nearest(@NotNull @NotNullElement List<PlayRoleBook> books) {
        if(CollectionUtils.isEmpty(books)){
            return Collections.emptyList();
        }
        Set<Long> fileIds = books.stream().map(PlayRoleBook::getFileId).filter(Objects::nonNull).collect(Collectors.toSet());
        if(fileIds.isEmpty()){
            return Collections.emptyList();
        }
        String idStr = String.join(",",fileIds.stream().map(String::valueOf).collect(Collectors.toSet()));
        return executeListSelect(String.format("id in (select max(id) as id from %s where fileId in(%s) group by fileId)",PlayRoleBookInstance.class.getSimpleName(),idStr));
    }

    @Nullable
    @Override
    public PlayRoleBookInstance find(@Nullable Iterable<PlayRoleBookInstance> iterable, @Nullable Long fileId) {
        if(fileId == null || iterable==null){
            return null;
        }
        for(PlayRoleBookInstance it : iterable){
            if(it == null){
                continue;
            }
            if(Objects.equals(fileId,it.getFileId())){
                return it;
            }
        }
        return null;
    }

    @NotNull
    @NotNullElement
    @Override
    public List<PlayRoleBookVo> books(@Nullable Long movieInstanceId) {
        List<BookChapterInstance> chapters = bookChapterInstanceService.listByProperty("movieInstanceId",movieInstanceId,"sequence");
        if(chapters.isEmpty()){
            return Collections.emptyList();
        }
        Set<Long> chapterInstanceIds = chapters.stream().map(BookChapterInstance::getId).collect(Collectors.toSet());
        if(chapterInstanceIds.isEmpty()){
            return Collections.emptyList();
        }
        List<PlayRoleBookInstance> books = listInProperty("chapterInstanceId",chapterInstanceIds);
        List<PlayRoleInstance> roles = playRoleInstanceService.listByProperty("movieInstanceId",movieInstanceId);
        List<PlayRoleBookVo> list = new ArrayList<>();
        for(PlayRoleInstance role : roles){
            for(BookChapterInstance chapter : chapters){
                PlayRoleBookInstance bookInstance = books.stream().filter(book->Objects.equals(book.getChapterInstanceId(),chapter.getId())
                        && Objects.equals(book.getPlayRoleInstanceId(),role.getId())).findFirst().orElse(null);
                if(bookInstance == null){
                    continue;
                }
                PlayRoleBookVo vo = new PlayRoleBookVo();
                vo.setId(bookInstance.getPlayRoleBookId());
                vo.setSequence(chapter.getSequence());
                vo.setName(chapter.getName());
                vo.setPlayRoleId(role.getPlayRoleId());
                vo.setChapterId(chapter.getChapterId());
                vo.setFilePath(bookInstance.getHtmlPath());
                list.add(vo);
            }
        }
        return list;
    }

    @Nullable
    @Override
    public String digest(@Nullable Long movieInstanceId, @Nullable Long playRoleBookId) {
        List<BookChapterInstance> chapters = bookChapterInstanceService.listByProperty("movieInstanceId",movieInstanceId,"sequence");
        if(chapters.isEmpty()){
            return null;
        }
        Set<Long> chapterInstanceIds = chapters.stream().map(BookChapterInstance::getId).collect(Collectors.toSet());
        if(chapterInstanceIds.isEmpty()){
            return null;
        }
        List<PlayRoleBookInstance> books = listInProperty("chapterInstanceId",chapterInstanceIds);
        PlayRoleBookInstance inst = books.stream().filter(book->Objects.equals(book.getPlayRoleBookId(),playRoleBookId)).findFirst().orElse(null);
        if(inst == null){
            return null;
        }
        return playRoleBookFileService.digest(inst.getHtmlId());
    }

    @Nullable
    @Override
    public String storePath(@Nullable Long movieInstanceId, @Nullable Long playRoleBookId) {
        List<BookChapterInstance> chapters = bookChapterInstanceService.listByProperty("movieInstanceId",movieInstanceId,"sequence");
        if(chapters.isEmpty()){
            return null;
        }
        Set<Long> chapterInstanceIds = chapters.stream().map(BookChapterInstance::getId).collect(Collectors.toSet());
        if(chapterInstanceIds.isEmpty()){
            return null;
        }
        List<PlayRoleBookInstance> books = listInProperty("chapterInstanceId",chapterInstanceIds);
        PlayRoleBookInstance inst = books.stream().filter(book->Objects.equals(book.getPlayRoleBookId(),playRoleBookId)).findFirst().orElse(null);
        if(inst == null){
            return null;
        }
        return playRoleBookFileService.storePath(inst.getHtmlId());
    }

    @Override
    public void downloadFile(HttpServletResponse response, Long movieInstanceId, Long playRoleBookId) {
        List<BookChapterInstance> chapters = bookChapterInstanceService.listByProperty("movieInstanceId",movieInstanceId,"sequence");
        if(chapters.isEmpty()){
            return;
        }
        Set<Long> chapterInstanceIds = chapters.stream().map(BookChapterInstance::getId).collect(Collectors.toSet());
        if(chapterInstanceIds.isEmpty()){
            return;
        }
        List<PlayRoleBookInstance> books = listInProperty("chapterInstanceId",chapterInstanceIds);
        PlayRoleBookInstance inst = books.stream().filter(book->Objects.equals(book.getPlayRoleBookId(),playRoleBookId)).findFirst().orElse(null);
        if(inst == null){
            return;
        }
        BookChapterInstance chapter = IdOperators.find(chapters,inst.getChapterInstanceId());
        playRoleBookFileService.downloadFile(response,inst.getHtmlId(),chapter != null?chapter.getName():inst.getHtmlPath());
    }

    @NotNull
    @NotNullElement
    public List<PlayRoleBookImage> images(@Nullable Long movieInstanceId, @Nullable Long playRoleBookId){
        List<BookChapterInstance> chapters = bookChapterInstanceService.listByProperty("movieInstanceId",movieInstanceId,"sequence");
        if(chapters.isEmpty()){
            return Collections.emptyList();
        }
        Set<Long> chapterInstanceIds = chapters.stream().map(BookChapterInstance::getId).collect(Collectors.toSet());
        if(chapterInstanceIds.isEmpty()){
            return Collections.emptyList();
        }
        List<PlayRoleBookInstance> books = listInProperty("chapterInstanceId",chapterInstanceIds);
        PlayRoleBookInstance inst = books.stream().filter(book->Objects.equals(book.getPlayRoleBookId(),playRoleBookId)).findFirst().orElse(null);
        if(inst == null){
            return Collections.emptyList();
        }
        return playRoleBookImageService.listByProperty("playRoleBookInstanceId",inst.getId());
    }

    @Override
    public void markFileDeleted(@Nullable @NullElement Collection<Long> ids) {
        batchUpdate("fileDeleted",1, ids);
    }
}
